package com.travelsky.client;

import java.awt.Frame;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JOptionPane;

import com.travelsky.server.vo.group.ProjectGroup;

/**
 * 代码提交工具-客户端
 ******************************************
 * @author HuangFeng  [2017年7月5日 上午11:11:40]
 * @version 1.0
 ******************************************
 */
public class Client extends Thread {

	/**
	 * 套接字
	 */
	private Socket c_socket;
	
	/**
	 * 工具主窗口
	 */
	private Client_chatFrame c_chatFrame;
	
	/**
	 * 登录窗口
	 */
	private Client_enterFrame c_enterFrame;
	
	/**
	 * 数据输入流
	 */
	private DataInputStream dis = null;
	
	/**
	 * 数据输出流
	 */
	private DataOutputStream dos = null;
	
	private ObjectInputStream ois = null;  
	private ObjectOutputStream oos = null;
	
	/**
	 * 退出标志
	 */
	private boolean flag_exit = false;
	
	/**
	 * 当前锁定人
	 */
	private String lockTokenUser = "";
	
	private Date lockTime = new Date();
	
	/**
	 * 第一个等待令牌的人
	 */
	private String firstWaitUser = "";
	
	/**
	 * Git最新状态 Success, running ,failed
	 */
	private String gitStatus = "";
	
	/**
	 * Git最新提交ID
	 */
	private String gitId = "";
	
	/**
	 * 用户锁定前Git的提交ID
	 */
	private String gitLockId = "";
	
	/**
	 * Git最新提交用户
	 */
	private String gitLastUpdateUser = "";
	
	/**
	 * 当前线程ID
	 */
	private int threadID;

	/**
	 * 信息
	 */
	private String chat_re;
	
	/**
	 * 定时器对象
	 */
	private Timer heartBeatTimer;
	
	/**
	 * 心跳定时任务
	 */
	private TimerTask heartBeatTask;
	
	/**
	 * 单人聊天窗口集合
	 */
	public Map<String, Client_singleFrame> c_singleFrames;
	
	/**
	 * 在线用户名字集合
	 */
	public List<String> username_online;
	
	/**
	 * 用户id集合
	 */
	public List<Integer> clientuserid;
	
	/**
	 * 当前用户名
	 */
	public String username = null;
	
	/**
	 * 当前项目组
	 */
	public String groupName = null;
	
	/**
	 * 客户端版本
	 */
	public String version = "V1.5.2";
	public List<ProjectGroup> projectGroupList;
	private String hostIp = "172.26.20.99";
	private String hostPort = "5000";

	/**
	 * 构造方法
	 ******************************************
	 * @author HuangFeng [2017年7月5日 上午11:32:29]
	 * @version 1.0
	 ******************************************
	 */
	@SuppressWarnings("unchecked")
	public Client() {
		try {
			c_socket = new Socket(hostIp, Integer.parseInt(hostPort));
			dos = new DataOutputStream(c_socket.getOutputStream());
			dis = new DataInputStream(c_socket.getInputStream());
			oos = new ObjectOutputStream(c_socket.getOutputStream());
			ois = new ObjectInputStream(c_socket.getInputStream());  
        	projectGroupList = (List<ProjectGroup>)ois.readObject();
		}catch(Exception e){
			System.exit(0);
		}
		c_singleFrames = new HashMap<String, Client_singleFrame>();
		username_online = new ArrayList<String>();
		clientuserid = new ArrayList<Integer>();
	}

	public static void main(String[] args) {
		Client client = new Client();
		//启动客户端
		client.startClient(); 
	}
	
	public void startClient(){
		c_enterFrame = new Client_enterFrame(this);
		c_enterFrame.setVisible(true);
		this.flag_exit = true;
		this.start();// 启动线程
		startHeartBeatThread();//启动心跳线程
	}
	
	public void run() {
		while (flag_exit) {
			validateLockTimeout();
			try {
				chat_re = dis.readUTF();
			} catch (IOException e) {
				flag_exit = false;
				c_chatFrame.closeClient("断网了，请重新登录");
			}
			if (chat_re != null) {
				if (chat_re.contains("@lockToken")) {
					String[] info = chat_re.split("@lockToken");
					c_chatFrame.setLockOrRealse(info[1]);
				} else if (chat_re.contains("@releaseToken")) {
					String[] info = chat_re.split("@releaseToken");
					c_chatFrame.setLockOrRealse(info[1]);
				}
				if (chat_re.contains("@updateVersion")) {
					String[] info = chat_re.split("@updateVersion");
					autoApdateVersion(info[0]);
				} else if (chat_re.contains("@clientThread")) {
					String[] info = chat_re.split("@clientThread");
					setThreadID(Integer.parseInt(info[0]));
					c_chatFrame.setLockOrRealse(info[1]);
					c_chatFrame.updateQueue(info[2]);
					c_chatFrame.git_url = info[3];
					c_chatFrame.sonar_url = info[4];
				} else if (chat_re.contains("@userlist")) {
					c_chatFrame.setDisUsers(chat_re);
				} else if (chat_re.contains("@serverexit")) {
					c_chatFrame.closeClient("服务器已关闭");
				} else if (chat_re.contains("@chat")) {
					c_chatFrame.setDisMess(chat_re);
				} else if (chat_re.contains("@single")) {
					c_chatFrame.setSingleFrame(chat_re);
				} else if (chat_re.contains("@Git@Sonar")) {
					c_chatFrame.updateGitAndSonarStatus(chat_re);
				} else if (chat_re.contains("@queue")) {
					c_chatFrame.updateQueue(chat_re);
				} else if (chat_re.contains("@forceQuit")) {
					c_chatFrame.forceQuit(chat_re);
				} else if (chat_re.contains("@timeTask")) {
					c_chatFrame.timeTask(chat_re);
				}
			}
		}
	}
	
	/**
	 * 校验锁定令牌是否超时
	 ******************************************
	 * @author HuangFeng [2017年12月11日 下午1:54:34]
	 * @version 1.0
	 ******************************************
	 */
	private void validateLockTimeout() {
		if(lockTokenUser.equals(username) && 
				(gitId.equals(gitLockId) || !gitLastUpdateUser.equals(username))){
			Long now = new Date().getTime();
			if (now - lockTime.getTime() > 1000*60*5 ) {
				c_chatFrame.setExtendedState(Frame.NORMAL); // 正常化状态
				c_chatFrame.setVisible(true);
				if (JOptionPane.OK_OPTION == JOptionPane.showConfirmDialog(c_chatFrame, "亲,还要提代码不？\n还要提就点确认,不提了就点取消", "提示",
						JOptionPane.OK_CANCEL_OPTION)) {
					lockTime = new Date();
				}else{
					releaseToken();
				}
			}
		}
	}

	/**
	 * 登录方法
	 ******************************************
	 * @author HuangFeng [2017年7月5日 上午11:34:40]
	 * @version 1.0
	 ******************************************
	 * @param username 用户名
	 * @param hostIp 服务器IP
	 * @param hostPort 服务器端口号
	 * @return 结果
	 */
	public void login(String groupName, String username) {
		this.groupName = groupName;
		this.username = username;
		c_enterFrame.setVisible(false);
		c_chatFrame = new Client_chatFrame(this);
		c_chatFrame.setVisible(true);
		try {
			dos.writeUTF(groupName+"@login"+username+"@login");
		} catch (IOException e) {
			c_enterFrame.closeClient("断网了，请重新登录");
		}
	}
	
	/**
	 * 启动心跳线程
	 ******************************************
	 * @author HuangFeng [2017年10月26日 下午3:07:10]
	 * @version 1.0
	 ******************************************
	 */
	public void startHeartBeatThread() {  
        // 启动心跳线程  
        heartBeatTimer = new Timer();  
        heartBeatTask = new TimerTask() {  
            @Override  
            public void run() {  
            	try {
					dos.writeUTF("heartpackage");
				} catch (IOException e) {
					c_chatFrame.closeClient("断网了，请重新登录");
				}
            }  
        };  
        heartBeatTimer.schedule(heartBeatTask, 5000, 5000);
    }  

	/**
	 * 自动更新版本
	 ******************************************
	 * @author HuangFeng [2017年10月23日 上午10:46:36]
	 * @version 1.0
	 ******************************************
	 * @param serverVersion 服务器端版本号
	 */
	public void autoApdateVersion(String serverVersion){
		// 如果服务器版本跟本地版本不一致
		if (!serverVersion.equals(version)) {
			try {
				heartBeatTimer.cancel();
				dos.writeUTF(version + "@updateVersion");
				String updaeMessage = "";
				updaeMessage = dis.readUTF();
				// 本地保存路径
				String savePath = c_enterFrame.chooseFolder(updaeMessage)+"\\";
				if (savePath.equals("\\")) {
					dos.writeUTF("stop");
					c_enterFrame.closeClient("接受文件失败");
				}
				dos.writeUTF("begin");
				int bufferSize = 8192;
				byte[] buf = new byte[bufferSize];
				//int passedlen = 0;
				//long len = 0;
				savePath += dis.readUTF();
				DataOutputStream fileOut = new DataOutputStream(
						new BufferedOutputStream(new FileOutputStream(savePath)));
				//len = dis.readLong();
				while (true) {
					int read = 0;
					if (dis != null) {
						read = dis.read(buf);
					}
					//passedlen += read;
					if (read == -1) {
						break;
					}
					// 下面进度条本为图形界面的prograssBar做的，这里如果是打文件，可能会重复打印出一些相同的百分比
					//System.out.println("文件接收了" + (passedlen * 100 / len) + "%\n");
					fileOut.write(buf, 0, read);
				}
				JOptionPane.showMessageDialog(c_enterFrame, "接收完成,新版本存放在:" + savePath+"\n"+"请用新版本重新登录");
				fileOut.close();
				exitChat();
			} catch (IOException e) {
				c_enterFrame.closeClient("接受文件失败");
			}
		}
	}
	
	/**
	 * 发送消息
	 ******************************************
	 * @author HuangFeng [2017年7月5日 上午11:38:09]
	 * @version 1.0
	 ******************************************
	 * @param mess 消息
	 */
	public void transMess(String mess) {
		try {
			dos.writeUTF(username + "@chat" + mess + "@chat");
		} catch (IOException e) {
			c_chatFrame.closeClient("断网了，请重新登录");
		}
	}

	/**
	 * 退出主窗口
	 ******************************************
	 * @author HuangFeng [2017年7月5日 上午11:38:26]
	 * @version 1.0
	 ******************************************
	 */
	public void exitChat() {
		//如果当前处于锁定状态
		if (lockTokenUser.equals(username)) {
			//释放令牌
			releaseToken();
		}
		try {
			dos.writeUTF(username + "@exit" + getThreadID() + "@exit");
			flag_exit = false;
			System.exit(0);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 退出登录窗口
	 ******************************************
	 * @author HuangFeng [2017年7月5日 上午11:39:38]
	 * @version 1.0
	 ******************************************
	 */
	public void exitLogin() {
		System.exit(0);
	}

	/**
	 * 退出客户端
	 ******************************************
	 * @author HuangFeng [2017年7月5日 上午11:41:08]
	 * @version 1.0
	 ******************************************
	 */
	public void exitClient() {
		flag_exit = false;
		System.exit(0);
	}

	/**
	 * 锁定令牌
	 ******************************************
	 * @author HuangFeng [2017年7月5日 上午11:41:23]
	 * @version 1.0
	 ******************************************
	 */
	public void lockToken() {
		try {
			//保存锁定之前Git最新提交ID
			gitLockId = gitId;
			dos.writeUTF(username + "@lockToken");
			lockTime = new Date();
		} catch (IOException e) {
			c_chatFrame.closeClient("断网了，请重新登录");
		}
	}

	/**
	 * 释放令牌
	 ******************************************
	 * @author HuangFeng [2017年7月5日 上午11:42:08]
	 * @version 1.0
	 ******************************************
	 */
	public void releaseToken() {
		try {
			dos.writeUTF(username + "@releaseToken");
			lockTime = new Date();
		} catch (IOException e) {
			c_chatFrame.closeClient("断网了，请重新登录");
		}
	}
	
	/**等待令牌
	 ******************************************
	 * @author HuangFeng [2017年7月4日 下午6:12:26]
	 * @version 1.0
	 ******************************************
	 */
	public void waitToken(String status) {
		if(status.equals("等待令牌")){
			try {
				dos.writeUTF(username + "@waitToken");
			} catch (IOException e) {
				c_chatFrame.closeClient("断网了，请重新登录");
			}
		}else{
			try {
				dos.writeUTF(username + "@canelWaitToken");
			} catch (IOException e) {
				c_chatFrame.closeClient("断网了，请重新登录");
			}
		}
	}

	/**
	 * 获取 threadID
	 * @return the threadID
	 */
	public int getThreadID() {
		return threadID;
	}

	/**
	 * 设置 threadID
	 * @param threadID the threadID to set
	 */
	public void setThreadID(int threadID) {
		this.threadID = threadID;
	}

	/**
	 * 获取 clientuserid
	 * @return the clientuserid
	 */
	public List<Integer> getClientuserid() {
		return clientuserid;
	}

	/**
	 * 设置 clientuserid
	 * @param clientuserid the clientuserid to set
	 */
	public void setClientuserid(List<Integer> clientuserid) {
		this.clientuserid = clientuserid;
	}

	/**
	 * 获取 username
	 * @return the username
	 */
	public String getUsername() {
		return username;
	}

	/**
	 * 设置 username
	 * @param username the username to set
	 */
	public void setUsername(String username) {
		this.username = username;
	}

	/**
	 * 获取 c_singleFrames
	 * @return the c_singleFrames
	 */
	public Map<String, Client_singleFrame> getC_singleFrames() {
		return c_singleFrames;
	}

	/**
	 * 设置 c_singleFrames
	 * @param c_singleFrames the c_singleFrames to set
	 */
	public void setC_singleFrames(Map<String, Client_singleFrame> c_singleFrames) {
		this.c_singleFrames = c_singleFrames;
	}

	/**
	 * 获取 dos
	 * @return the dos
	 */
	public DataOutputStream getDos() {
		return dos;
	}

	/**
	 * 设置 dos
	 * @param dos the dos to set
	 */
	public void setDos(DataOutputStream dos) {
		this.dos = dos;
	}

	/**
	 * 获取 username_online
	 * @return the username_online
	 */
	public List<String> getUsername_online() {
		return username_online;
	}

	/**
	 * 设置 username_online
	 * @param username_online the username_online to set
	 */
	public void setUsername_online(List<String> username_online) {
		this.username_online = username_online;
	}

	/**
	 * 获取 firstWaitUser
	 * @return the firstWaitUser
	 */
	public String getFirstWaitUser() {
		return firstWaitUser;
	}

	/**
	 * 设置 firstWaitUser
	 * @param firstWaitUser the firstWaitUser to set
	 */
	public void setFirstWaitUser(String firstWaitUser) {
		this.firstWaitUser = firstWaitUser;
	}

	/**
	 * 获取 gitStatus
	 * @return the gitStatus
	 */
	public String getGitStatus() {
		return gitStatus;
	}

	/**
	 * 设置 gitStatus
	 * @param gitStatus the gitStatus to set
	 */
	public void setGitStatus(String gitStatus) {
		this.gitStatus = gitStatus;
	}

	/**
	 * 获取 gitLockId
	 * @return the gitLockId
	 */
	public String getGitLockId() {
		return gitLockId;
	}

	/**
	 * 设置 gitLockId
	 * @param gitLockId the gitLockId to set
	 */
	public void setGitLockId(String gitLockId) {
		this.gitLockId = gitLockId;
	}

	/**
	 * 获取 gitLastUpdateUser
	 * @return the gitLastUpdateUser
	 */
	public String getGitLastUpdateUser() {
		return gitLastUpdateUser;
	}

	/**
	 * 设置 gitLastUpdateUser
	 * @param gitLastUpdateUser the gitLastUpdateUser to set
	 */
	public void setGitLastUpdateUser(String gitLastUpdateUser) {
		this.gitLastUpdateUser = gitLastUpdateUser;
	}

	/**
	 * 获取 lockTokenUser
	 * @return the lockTokenUser
	 */
	public String getLockTokenUser() {
		return lockTokenUser;
	}

	/**
	 * 设置 lockTokenUser
	 * @param lockTokenUser the lockTokenUser to set
	 */
	public void setLockTokenUser(String lockTokenUser) {
		this.lockTokenUser = lockTokenUser;
	}

	/**
	 * 获取 gitId
	 * @return the gitId
	 */
	public String getGitId() {
		return gitId;
	}

	/**
	 * 设置 gitId
	 * @param gitId the gitId to set
	 */
	public void setGitId(String gitId) {
		this.gitId = gitId;
	}

	/**
	 * 获取 oos
	 * @return the oos
	 */
	public ObjectOutputStream getOos() {
		return oos;
	}

	/**
	 * 设置 oos
	 * @param oos the oos to set
	 */
	public void setOos(ObjectOutputStream oos) {
		this.oos = oos;
	}
	
}
